package io.yizoo.system.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.cache.Cache;
import io.elm.core.CoreController;
import io.elm.core.saas.DSContext;
import io.elm.core.saas.SpringDataSourceConfig;
import io.elm.core.security.JwtUtils;
import io.yizoo.business.entity.biz_hrm_ei_basic;
import io.yizoo.business.entity.biz_hrm_ei_rel_org;
import io.yizoo.config.WorkWeixinConfig;
import io.yizoo.system.entity.sys_org;
import io.yizoo.system.entity.sys_role;
import io.yizoo.system.entity.sys_role_rel_user;
import io.yizoo.system.entity.sys_user;
import io.yizoo.system.util.HttpClientUtils;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("system/login/work/weixin/my")
public class login_workWeixinMyController extends CoreController {
    @Autowired
    private WorkWeixinConfig workWechatConfig;
    @Autowired
    private Map<String,Cache<String,String>> cacheMap;
    @Autowired
    private SpringDataSourceConfig springDataSourceConfig;
    @Autowired
    private JwtUtils jwtUtils;
    @Autowired
    private io.yizoo.system.mapper.sys_menuMapper sys_menuMapper;
    private static final String TO_TYPE_USER = "USER";
    private static final String IGNORE_LEN = "@all";

    @Override
    protected void Init() {
        PowerEntity = sys_user.class;
        PowerUse = EnumSet.of(Power.IDDelete, Power.IDAny, Power.IDGetSingle);
    }

    private static final String SUITE_TICKET = "SuiteTicket";
    private static final String SUITE_ID = "SuiteId";
    private static final String INFO_TYPE = "InfoType";
    private static final String AUTH_CODE = "AuthCode";

//    @GetMapping("/data")
//    public Object callBackData(@RequestParam("msg_signature") String msgSignature,
//                               @RequestParam("timestamp") String timestamp,
//                               @RequestParam("nonce") String nonce,
//                               @RequestParam("echostr") String echostr) {
//        return verifySignature(msgSignature, timestamp, nonce, echostr);
//    }

    private  Map<String,Object> getConfig(String key) {
        List<Map<String, Object>> dataSet = DSContext.DATA_SET;
        if (dataSet == null) {
            return null;
        }
        Map<String,Object> result = new HashMap<>();
        for (Map<String, Object> map : dataSet) {
            if (map.get("key").equals(key)) {
                result.putAll(map);
                return result;
            }

        }

        return null;
    }

    /**
     * 跳转企业微信授权页
     * @return
     */
    @PostMapping("/redirectUrl")
    public Object redirectUrl(@RequestParam("key")String key) {
        Map<String, Object> config = getConfig(key);
        if (config == null) {
            return "请联系企业管理员开通权限";
        }
        String redirectUrl = getRedirectUrl(key);
        try {
            String encode = URLEncoder.encode(redirectUrl, "UTF-8");
            String url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid="+(String) config.get("corp_id")+"&redirect_uri="+encode+"&response_type=code&scope=snsapi_userinfo&agentid="+config.get("agent_id")+"&state=STATE#wechat_redirect";

            return JsonResult(new KV("url", url));
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
    }
    private String getRedirectUrl(String key) {
        return "http://www.snbg365.com/v/system/login?loginType=workWeixinMy&type=login&key="+key;
    }

    @PostMapping("/login")
    public Object login(@RequestParam("code") String code,@RequestParam(value = "key",required = false) String key) {
        Map<String, Object> config = getConfig(key);
        if (config == null) {
            return "请联系企业管理员开通权限,请联系系统管理员";
        }
        String accessToken = getAccessToken(key, config);
        if (accessToken == null) {
            return "获取accessToken失败,请联系系统管理员";
        }
        String result = getUserTicket(code, accessToken);
        if (result == null) return "获取用户信息失败,请联系系统管理员";

        String userId = getUserId(result, accessToken);
        if (userId == null) {
            return "获取用户ID失败,请联系系统管理员";
        }
        String name = getUserName(accessToken, userId);
        if (name == null) {
            return "获取用户姓名失败,请联系系统管理员";
        }
        sys_user user_mod = Ctor.HMapper.GetSingle(sys_user.class,
                Ctor.DMaker().Selector
                        .From(sys_user.class)
                        .IsWhere("and user_name = #{"+name+"}",null)
                        .Limit("limit 1")
                        .GetFactor());
        if (user_mod == null) {

            return "未查询到人员信息,请联系系统管理员";
        } else {
            String userName = user_mod.getUser_name();
            final String token = jwtUtils.generateToken(userName+"."+key);
            userName = Ctor.GetCutUsername(userName);
            //若有人员关联，那么几个字段值用人员表记录的对应字段值
            boolean eiOrgExist = false;
            List<Map<String,Object>> check_ei = Ctor.CoreMapper.USelect(
                    Ctor.DMaker().Selector
                            .putFactorItem("id", user_mod.getId())
                            .Select("uu.*,ei.id AS ei_id,ei.name AS ei_name,ei.sex AS ei_sex,ei.phone AS ei_phone,oo.id AS ei_org_id")
                            .From(sys_user.class,"uu")
                            .LeftJoin(biz_hrm_ei_basic.class,"ei","ei.emp_code = uu.emp_code")
                            .LeftJoin(biz_hrm_ei_rel_org.class,"rr","rr.ei_id = ei.id AND rr.pm='1' ")
                            .LeftJoin(sys_org.class,"oo","oo.id = rr.org_id ")
                            .Where("AND uu.id = #{id}","id")
                            .GetFactor());
            if(check_ei.size()==1 && check_ei.get(0).get("ei_id")!=null){
                Map<String,Object> item = check_ei.get(0);
                if(item.get("ei_name")!=null){user_mod.setNick_name(item.get("ei_name").toString());}
                if(item.get("ei_org_id")!=null){user_mod.setDept_id(item.get("ei_org_id").toString());eiOrgExist = true;}
                //if(item.get("ei_phone")!=null){user_mod.setPhonenumber(item.get("ei_phone").toString());}
                //if(item.get("ei_sex")!=null){user_mod.setSex(item.get("ei_sex").toString());}
            }
            sys_org org_mod = Ctor.HMapper.GetSingle(sys_org.class,
                    Ctor.DMaker().Selector.From(sys_org.class, "t")
                            .putFactorItem("id", name)
                            .LeftJoin(sys_user.class, "a", "a.dept_id=t.id")
                            .Where("and a.user_name=#{id}").GetFactor()
            );
            if(eiOrgExist){
                org_mod = Ctor.HMapper.GetSingle(sys_org.class,
                        Ctor.DMaker().Selector.From(sys_org.class, "t")
                                .putFactorItem("id", user_mod.getDept_id())
                                .Where("and t.id=#{id}").GetFactor()
                );
            }
            Object roles = Ctor.CoreMapper.USelect(
                    Ctor.DMaker(JSON.toJSONString(user_mod)).Selector.From(sys_role.class, "t")
                            .Select("t.*")
                            .putFactorItem("user_id", user_mod.getId())
                            .LeftJoin(sys_role_rel_user.class, "a", "a.role_id=t.id")
                            .Where("and a.user_id=#{user_id}").GetFactor()
            );
            Object menu_data = sys_menuMapper.SelectUserMenuTree(
                    Ctor.DMaker().Selector.putFactorItem("user_id", user_mod.getId()).GetFactor()
            );

            Map<String, Object> map = JsonResult(
                    new KV("token", token),
                    new KV("success", true),
                    new KV("authpage", ""),
                    new KV("menu", menu_data),
                    new KV("user",
                            new KV("name", user_mod.getNick_name())),
                    new KV("org",
                            new KV("name", org_mod == null ? "" : org_mod.getName())),
                    new KV("role", roles),
                    new KV("system",
                            new KV("path", "/system/main"),
                            new KV("name", "主页"))
            );
            System.out.println("work weixin login result: "+JSON.toJSONString(map));

            return map;
        }


    }

    /**
     * 地址 https://developer.work.weixin.qq.com/document/path/90236
     * {
     *    "touser" : "UserID1|UserID2|UserID3",
     *    "toparty" : "PartyID1 | PartyID2",
     *    "totag" : "TagID1 | TagID2",
     *    "msgtype" : "textcard",
     *    "agentid" : 1,
     *    "textcard" : {
     *             "title" : "领奖通知",
     *             "description" : "<div class=\"gray\">2016年9月26日</div> <div class=\"normal\">恭喜你抽中iPhone 7一台，领奖码：xxxx</div><div class=\"highlight\">请于2016年10月10日前联系行政同事领取</div>",
     *             "url" : "URL",
     *                         "btntxt":"更多"
     *    },
     *    "enable_id_trans": 0,
     *    "enable_duplicate_check": 0,
     *    "duplicate_check_interval": 1800
     * 字段名
     * touser	否	成员ID列表（消息接收者，多个接收者用‘|’分隔，最多支持1000个）。特殊情况：指定为@all，则向关注该企业应用的全部成员发送
     * toparty	否	部门ID列表，多个接收者用‘|’分隔，最多支持100个。当touser为@all时忽略本参数
     * totag	否	标签ID列表，多个接收者用‘|’分隔，最多支持100个。当touser为@all时忽略本参数
     * msgtype	是	消息类型，此时固定为：textcard
     * agentid	是	企业应用的id，整型。企业内部开发，可在应用的设置页面查看；第三方服务商，可通过接口 获取企业授权信息 获取该参数值
     * title	是	标题，不超过128个字符，超过会自动截断（支持id转译）
     * description	是	描述，不超过512个字符，超过会自动截断（支持id转译）
     * url	是	点击后跳转的链接。最长2048字节，请确保包含了协议头(http/https)
     * btntxt	否	按钮文字。 默认为“详情”， 不超过4个文字，超过自动截断。
     * enable_id_trans	否	表示是否开启id转译，0表示否，1表示是，默认0
     * enable_duplicate_check	否	表示是否开启重复消息检查，0表示否，1表示是，默认0
     * duplicate_check_interval	否	表示是否重复消息检查的时间间隔，默认1800s，最大不超过4小时
     * }
     * @param jsonStr
     * @return
     */
    @PostMapping("/sendCardMsg")
    public Object sendCardMessage(@RequestBody String jsonStr) {
        JSONObject param = JSONObject.parseObject(jsonStr);
        String key = param.getString("key");
        if (param.getString("key") == null) {
            return "请输入key";
        }

        String title = param.getString("title");
        if (title == null) {
            throw new RuntimeException("请输入发送标题");
        }
        if (title.length() >= 128) {
            throw new RuntimeException("发送内容不能超过128个字节");
        }
        String description = param.getString("title");
        if (description == null) {
            throw new RuntimeException("请输入发送内容");
        }
        if (description.length() >= 512) {
            throw new RuntimeException("发送内容不能超过512个字节");
        }
        String url = param.getString("url");
        if (url.length() >= 2048) {
            throw new RuntimeException("发送内容不能超过2048个字节");
        }

        String toTarget = param.getString("toTarget");
        if (toTarget == null) {
            throw new RuntimeException("请输入接收人员");
        }
        String toType = param.getString("toType");
        if (StringUtils.isEmpty(toType)) {
            toType = "user";
        }
        if (!toTarget.equals("IGNORE_LEN")) {
            String[] split = toTarget.split("|");
            if (split.length > 100) {
                throw new RuntimeException("接收人员不能超过100个");
            }
        }
        String toTargetKey = "touser";
        if (toType.equals("party")) {
            toTargetKey = "toparty";
        } else if (toType.equals("tag")) {
            toTargetKey = "totag";
        }
        Map<String,String> textCard = new HashMap<>();
        Map<String, Object> config = getConfig(key);
        Map<String, Object> map = new HashMap<>();
        map.put(toTargetKey, toTarget);
        map.put("agentid", config.get("agent_id"));
        textCard.put("title", title);
        textCard.put("description", description);
        map.put("textcard",textCard);
        map.put("msgtype","textcard");
        map.put("url",getRedirectUrl(key));

        String accessToken = getAccessToken(key, config);
        if (accessToken == null) {
            return "获取accessToken失败";
        }
        String sendUrl = " https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token="+accessToken;
        String result = HttpClientUtils.doPost(sendUrl, map);
        System.out.println("发送卡片消息："+result);
        return result;

    }

    private static String getUserName(String accessToken, String userId) {
        String getUserUrl = "https://qyapi.weixin.qq.com/cgi-bin/user/get";
        Map<String, Object> userParmMap = new HashMap<>();
        userParmMap.put("access_token", accessToken);
        userParmMap.put("userid", userId);
        String userStr = HttpClientUtils.doPost(getUserUrl, userParmMap);
        String name = (String)JSONObject.parseObject(userStr).get("name");
        return name;
    }

    @Nullable
    private static String getUserId(String result, String accessToken) {
        String userTicket = JSONObject.parseObject(result).getString("user_ticket");
        String userDetailUrl = "https://qyapi.weixin.qq.com/cgi-bin/auth/getuserdetail?access_token="+ accessToken;
        Map<String, Object> detailPardamMap = new HashMap<>();
        detailPardamMap.put("user_ticket", userTicket);
        String detailStr = HttpClientUtils.doPost(userDetailUrl, detailPardamMap);
        System.out.println("用户信息详情："+ detailStr);

        JSONObject userJsongOb = JSONObject.parseObject(detailStr);
        String userId = (String)userJsongOb.get("user_id");
        if (userId == null) {
            return null;
        }
        return userId;
    }

    @Nullable
    private static String getUserTicket(String code, String accessToken) {
        String userUrl = "https://qyapi.weixin.qq.com/cgi-bin/auth/getuserinfo";
        Map<String, String> paramMap = new HashMap<>();
        paramMap.put("access_token", accessToken);
        paramMap.put("code", code);
        String result = HttpClientUtils.doGet(userUrl, paramMap);
        System.out.println("用户信息："+ result);
        if (result == null) {
            return null;
        }
        return result;
    }

    @Nullable
    private static String getAccessToken(String key, Map<String, Object> config) {
        // 获取accessToken
        String corpId = (String) config.get("corp_id");
        String secret = (String) config.get("secret");
        String accessTokenUrl = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid="+corpId+"&corpsecret="+secret;
        String accessToken = HttpClientUtils.doGet(accessTokenUrl,null);
        if (accessToken == null) {
            return null;
        }
        System.out.println("自建应用  key: "+ key + "accessToken:" + accessToken);
        return accessToken;
    }


    public static void main(String[] args) {
//        String xml = "<xml>\n" +
//                "<SuiteId><![CDATA[ww4asffe99e54c0fxxxx]]></SuiteId>\n" +
//                "<InfoType> <![CDATA[suite_ticket]]></InfoType>\n" +
//                "<TimeStamp>1403610513</TimeStamp>\n" +
//                "<SuiteTicket><![CDATA[asdfasfdasdfasdf]]></SuiteTicket>\n" +
//                "</xml>";
//
//
//        try {
//            Map map = XmlMapper.builder().build().readValue(xml, Map.class);
//            System.out.println(JSON.toJSONString(map));
//        } catch (JsonProcessingException e) {
//            throw new RuntimeException(e);
//        }
        String redirectUrl = "http://www.snbg365.com/api/system/login?loginType=workWeixin&key=gg";
            String encode = null;
            try {
                encode = URLEncoder.encode(redirectUrl, "UTF-8");
            } catch (UnsupportedEncodingException e) {
                throw new RuntimeException(e);
            }
            String url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=ww45eb3068dd994505&redirect_uri="+encode+"&response_type=code&scope=snsapi_userinfo&agentid=1000003&state=STATE#wechat_redirect";
            System.out.println(url);
    }
}
